package com.anneric;

import java.io.IOException;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.os.Bundle;
import android.util.Log;
import android.view.Display;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.AssetManager;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.drawable.BitmapDrawable;
import com.anneric.LevelsContainer;


public class MatchingGameActivity 
	extends Activity {
	
	private ProgressBar pbar_level;
	private ProgressBar pbar_game;
	private ImageView orig_pic;
	private ImageView modif_pic;
	private boolean spot_1_found;
	private boolean spot_2_found;
	LevelsContainer levels;
	Level current_level;
	PicInfoStorage current_layer;
	private int current_level_int = 0;
	private int current_layer_int = 0;
	private int click_tolerance = 10; // in percent of the image's dimensions
	private int curr_layout;
	

	
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
      	
        super.onCreate(savedInstanceState);
        setContentView(R.layout.start_screen);
        curr_layout = 0;
        
        // starts with buttonStart() onClick-Event of buttonStart of start_screen layout

    }
    
    /** Called (amongst other) when screen is rotated; tells Android, that 
     * this Activity will handle all necessary changes itself ===> discouraged in documentation
     * see http://developer.android.com/guide/topics/resources/runtime-changes.html */
    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        if (curr_layout > 0){
            setMainLayout();
            loadLayerInfoToLayout();
            updateLevelText();
            updateProgressBars();
        }
    }

	private void configureProgressBars() {
		
    	resetCounter(); //init
    	
    	pbar_level = (ProgressBar) findViewById(R.id.progress_level);
        pbar_game = (ProgressBar) findViewById(R.id.progress_game);
        
        pbar_level.setMax(100);
        pbar_game.setMax(100);

		resetPBars();
	}

	public void startGame() throws IOException{
    	
		//TODO: wrap in extra thread to prevent lag when parsing big file
    	AssetManager am = getResources().getAssets();
    	levels = new LevelsContainer();
    	levels.load(am);
    	
    	if (!levels.isEmpty()){
    		runNextLevel();
    	} else {
    		throw new IOException("No level data found.");
    	}
    }
    
	
	private void runNextLevel() {
		
		current_level = levels.getNextLevel();
			
    	// prepare canvas for content update
    	if (current_level.getDifficulty() == 1){
    		orig_pic = (ImageView) this.findViewById(R.id.orig_pic);
    		modif_pic = (ImageView) this.findViewById(R.id.modif_pic);
    	} else {
    		orig_pic = (ImageView) this.findViewById(R.id.orig_pic);
    		modif_pic = (ImageView) this.findViewById(R.id.modif_pic);
    	}
    	
    	++current_level_int;
    	current_layer_int = 0;
    	runNextLayer();		
    	updateLevelText();
	}


	private void runNextLayer() {
		++current_layer_int;
		resetSpotFindings();
		current_layer = current_level.getNextLayer();
		loadLayerInfoToLayout();
		updateProgressBars();
	}
	
	/*
	public void onDraw(Canvas canvas) {

    }
    */

  	private void loadLayerInfoToLayout() {
 
		orig_pic = (ImageView) this.findViewById(R.id.orig_pic);
		modif_pic = (ImageView) this.findViewById(R.id.modif_pic);		

		orig_pic.setImageResource(  getDrawableIdfromFilename(  current_layer.getOPP() ) );
		modif_pic.setImageResource( getDrawableIdfromFilename(  current_layer.getMPP() ) );
		
		modif_pic.setOnTouchListener(
				new View.OnTouchListener() {
					@Override
			        public boolean onTouch(View v, MotionEvent event) {
						if (event.getAction() == MotionEvent.ACTION_DOWN){
							imageClicked(v, event);
			            }
			            return true;

					}
				}	
		);
	}
	
    private void imageClicked(View v, MotionEvent event){
    	int found = checkFound(event);
    	if (found != 0){
    		evalFinding(found);
    	}
    }


	private void evalFinding(int found) {
		
		if (current_level.getDifficulty() == 1){
			if (found == 1){
				spot_1_found = true; // <- probably not necessary with one button...	
				proceedGame();
			}
		} else {
			//diff == 2
			if (found == 1){
				if (!spot_1_found){
					spot_1_found = true;
					
					if (spot_2_found){
						//TODO: inter level actions
						//doProgressAnim(2);
						proceedGame();
					} else {
						doPopUp("Prima! Jetzt noch der andere!");
						//doProgressAnim(1);
					}
				}
			} else {
				assert(found == 2);
				if (!spot_2_found){
					spot_2_found = true;
					
					if (spot_1_found){
						//TODO: inter level actions
						//doProgressAnim(2);
						proceedGame();
					} else {
						doPopUp("Super! Noch einer!");
						//doProgressAnim(1);
					}
					
				}
			}
		}
		
	}
	
	public static int[] getBitmapOffset(ImageView img,  Boolean includeLayout) {
		// taken from http://stackoverflow.com/questions/6023549/android-how-to-get-the-image-edge-x-y-position-inside-imageview
		// coded by Shlomi Schwartz (changed offset[0] to represent x and [1] to represent y)
        int[] offset = new int[2];
        float[] values = new float[9];

        Matrix m = img.getImageMatrix();
        m.getValues(values);
        
        offset[0] = (int) values[2];
        offset[1] = (int) values[5];

        if (includeLayout) {
            ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) img.getLayoutParams();
            int paddingTop = (int) (img.getPaddingTop() );
            int paddingLeft = (int) (img.getPaddingLeft() );
            
            offset[0] += paddingLeft + lp.leftMargin;
            offset[1] += paddingTop + lp.topMargin;
            

        }
        return offset;
    }



	private int checkFound(MotionEvent event) {
		float raw_click_x = event.getRawX();
		float raw_click_y = event.getRawY();
		
		
		modif_pic = (ImageView) findViewById(R.id.modif_pic);
		int[] imgview_pos = new int[2];
		modif_pic.getLocationInWindow(imgview_pos);

		
		Bitmap b = ((BitmapDrawable)modif_pic.getDrawable()).getBitmap();
		float pic_width = b.getWidth();
		float pic_height = b.getHeight();
		
		int bitmap_offset[] = getBitmapOffset(modif_pic, true);
		
		float rel_click_x = raw_click_x - imgview_pos[0] - bitmap_offset[0];
		float rel_click_y = raw_click_y - imgview_pos[1] - bitmap_offset[1];
		
		float perc_click_x = rel_click_x / pic_width * 100;
		float perc_click_y = rel_click_y / pic_height * 100;
		
		
		/* debugging info
		String debuginf =	"raw click: " + String.valueOf(raw_click_x) + ", " + String.valueOf(raw_click_y) + "\n" +
							"pic pos: " + String.valueOf(imgview_pos[0]) + ", " + String.valueOf(imgview_pos[1]) + "\n" +
							"pic offs: " + String.valueOf(bitmap_offset[0]) + ", " + String.valueOf(bitmap_offset[1]) + "\n" +
							"rel click: " + String.valueOf(rel_click_x) + ", " + String.valueOf(rel_click_y) + "\n" +
							"pic dim: " + String.valueOf(pic_width) + ", " + String.valueOf(pic_height) + "\n" +
							"result: " + String.valueOf(perc_click_x) + ", " + String.valueOf(perc_click_y) + "\n" +
							"spot: " + String.valueOf(spot_x) + ", " + String.valueOf(spot_y);
							
		
		doPopUp(debuginf);
		*/		
		
		if (!spot_1_found){
			float spot_x = current_layer.getMarginL1();
    		float spot_y = current_layer.getMarginT1();
    		
    		if (pointInRectangle(perc_click_x, perc_click_y, spot_x, spot_y)){
    			return 1;
    		}
    		
		} //EO if spot 1 found
		
		if (current_level.getDifficulty() == 2){
			if (!spot_2_found){
				float spot_x = current_layer.getMarginL2();
	    		float spot_y = current_layer.getMarginT2();
	    		
	    		if (pointInRectangle(perc_click_x, perc_click_y, spot_x, spot_y)){
	    			return 2;
	    		}
			}			
		}
		
		return 0;
	}
	
	private boolean pointInRectangle(float x, float y, float rx, float ry){
		float tol = (float) click_tolerance;
		
		// if x within limits
		if ( (x >= rx - tol) &&	(x <= rx + tol)	){
			
			// if y within limits
			if ( (y >= ry - tol) &&	(y <= ry + tol)	){
				return true;
			}
		}
		
		return false;
	}


	private void proceedGame() {
		
		
		if (current_level.hasNextLayer()){
			runNextLayer();
		} else if(levels.hasNextLevel()) {
			runNextLevel();
		} else {
			doPopUp("Spitze! Du hast das Spiel geschafft!");
			setContentView(R.layout.win_screen);
			curr_layout = -1;
		}
		
	}
	
	
	//
    // Auxiliary functions
    //
  	
	private final int getDrawableIdfromFilename(String filename){
		return getResources().getIdentifier(filename, "drawable", getPackageName());
	}
	
    private void setMainLayout() {
		int orientation = getScreenOrientation();
		if (orientation == 2){
			setContentView(R.layout.game_main_land);
			curr_layout = 1;
		} else {
			setContentView(R.layout.game_main_port);
			curr_layout = 2;
		}
	}
    
    public int getScreenOrientation()
    // this function is from: http://stackoverflow.com/questions/2795833/check-orientation-on-android-phone
    // coded by Jarek Potiuk
    {
        Display getOrient = getWindowManager().getDefaultDisplay();
        int orientation = Configuration.ORIENTATION_UNDEFINED;
        if(getOrient.getWidth()==getOrient.getHeight()){
            orientation = Configuration.ORIENTATION_SQUARE;
        } else{ 
            if(getOrient.getWidth() < getOrient.getHeight()){
                orientation = Configuration.ORIENTATION_PORTRAIT;
            }else { 
                 orientation = Configuration.ORIENTATION_LANDSCAPE;
            }
        }
        return orientation;
    }

	
	private final void doPopUp(String descr){
		final AlertDialog.Builder alert = new AlertDialog.Builder(this);		
        alert.setMessage(descr);
        alert.setPositiveButton(R.string.button_ok,
                new DialogInterface.OnClickListener() {
        	
        			public void onClick(DialogInterface dialog,
                            int which) {
                        dialog.cancel();
                    }
                });
        alert.show();
	}
	
	// TODO: find out when/how to .show() this dialog
	@SuppressWarnings("unused")
	private final void doProgressAnim(int step){
		Context mContext = getApplicationContext();
		Dialog dialog = new Dialog(mContext);

		dialog.setContentView(R.layout.progress_dialog);
		
		ImageView image1 = (ImageView) dialog.findViewById(R.id.progress_dialog_image);

		
		assert(step == 1 || step == 2);
		
		if (step == 1){
			image1.setImageResource(R.drawable.fireworks_anim_00);
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			image1.setImageResource(R.drawable.fireworks_anim_01);
		} else {
			image1.setImageResource(R.drawable.fireworks_anim_01);
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			image1.setImageResource(R.drawable.fireworks_anim_02);
		}
		
	}
	
	// variable resetting
	//

	private void reset_game_status() {
		resetCounter();
		resetSpotFindings();
	}
	
	private void resetCounter() {
		current_level_int = 0;
		current_layer_int = 0;
	}


	private void resetPBars() {	
		pbar_level = (ProgressBar) findViewById(R.id.progress_level);
		pbar_game = (ProgressBar) findViewById(R.id.progress_game);
      	pbar_level.setProgress(0);
		pbar_game.setProgress(0);
	}

	private void resetSpotFindings() {
		spot_1_found = false;
		spot_2_found = false;
	}

  	// progress bars
	//
    
    private void updateProgressBars(){
 	
    	updateLevelProgress();
    	updateGameProgress();

    }
  	
    private void updateLevelProgress() {
    	
    	// reduce by one, to show what already has been reached and not where at
    	int currlayer = current_layer_int;
    	if (currlayer >= 1){
    		currlayer -= 1;
    	}
    	
    	final float prog = ( (float)currlayer / (float)current_level.getAmountOfLayers() ) * 100;
    	pbar_level = (ProgressBar) findViewById(R.id.progress_level);
    	pbar_level.setProgress((int)prog);
    	Log.i("LevelProgress", String.valueOf((int)prog));
	}
    
    private void updateGameProgress() {
    	
    	// reduce by one, to show what already has been reached and not where at
    	int currlevel = current_level_int;
    	if (currlevel >= 1){
    		currlevel -= 1;
    	}
    	
    	final float prog = ( (float)currlevel / (float)levels.getAmountOfLevels() ) * 100;
    	pbar_game = (ProgressBar) findViewById(R.id.progress_game);
    	pbar_game.setProgress((int)prog);
    	Log.i("GameProgress", String.valueOf((int)prog));
	}
	
	//
    // Button actions
    //

	private void updateLevelText() {
		String currlvl = this.getString(R.string.current_level);
		currlvl += " ";
		currlvl += String.valueOf(current_level_int);
		TextView LevelText = (TextView) findViewById(R.id.current_level_text);
		LevelText.setText(currlvl);
	}


	// initial start game button

	public void buttonStart(View v) throws IOException {
		
		Log.i("buttonStart","BEGIN");
		
		setMainLayout();

		configureProgressBars();

		startGame();

		Log.i("buttonStart","END");
	}
	
	// main menu button
	
	public void buttonHome(View v) {
		reset_game_status();
		setContentView(R.layout.start_screen);
		curr_layout = 0;
	}

}